 

/*-------------------------------------------------------------------------
 *
 * message.c
 *	  通用逻辑消息。
 *
 * Copyright (c) 2013-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/backend/replication/logical/message.c
 *
 * NOTES
 *
 * 通用逻辑消息允许以 XLOG 的方式记录任意二进制数据块，这些数据块
 * 会传递给逻辑解码插件。在正常的 XLOG 处理过程中，它们与 NOOP 是
 * 一样的。
 *
 * 这些消息可以是事务性的，也可以是非事务性的。
 * 事务性消息是当前事务的一部分，将以与 DML 操作相同的方式发送到
 * 解码插件。
 * 非事务性消息在逻辑解码从 XLOG 中读取它们时发送给插件。这也
 * 意味着，如果事务被回滚，则事务性消息不会被传递，但非事务性消息
 * 将始终被传递。
 *
 * 每条消息都带有前缀，以避免不同解码插件之间的冲突。插件作者
 * 必须特别注意使用唯一前缀，好的选择似乎比如使用扩展的名称。
 *
 * ---------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/xact.h"
#include "access/xloginsert.h"
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "replication/logical.h"
#include "replication/message.h"
#include "utils/memutils.h"

/*
 * 将逻辑解码信息写入XLog。
 */
XLogRecPtr LogLogicalMessage(const char *fc_prefix, const char *fc_message, size_t fc_size,
				  bool fc_transactional)
{
	xl_logical_message fc_xlrec;

	/*
	 * 如果我们正在发出事务性消息，则强制分配xid。
	 */
	if (fc_transactional)
	{
		Assert(IsTransactionState());
		GetCurrentTransactionId();
	}

	fc_xlrec.dbId = MyDatabaseId;
	fc_xlrec.transactional = fc_transactional;
	/* 尾随零是关键；请参见logicalmsg_desc */
	fc_xlrec.prefix_size = strlen(fc_prefix) + 1;
	fc_xlrec.message_size = fc_size;

	XLogBeginInsert();
	XLogRegisterData((char *) &fc_xlrec, SizeOfLogicalMessage);
	XLogRegisterData(unconstify(char *, fc_prefix), fc_xlrec.prefix_size);
	XLogRegisterData(unconstify(char *, fc_message), fc_size);

	/* 允许源过滤 */
	XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);

	return XLogInsert(RM_LOGICALMSG_ID, XLOG_LOGICAL_MESSAGE);
}

/*
 * 重做对于逻辑解码消息基本上只是无操作。
 */
void logicalmsg_redo(XLogReaderState *fc_record)
{
	uint8		fc_info = XLogRecGetInfo(fc_record) & ~XLR_INFO_MASK;

	if (fc_info != XLOG_LOGICAL_MESSAGE)
		elog(PANIC, "logicalmsg_redo: unknown op code %u", fc_info);

	/* 这对于逻辑解码来说是唯一有趣的，见decode.c。 */
}
